package com.danskin.wechat.webapi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jeewx.api.core.exception.WexinReqException;
import org.jeewx.api.mp.aes.AesException;
import org.jeewx.api.mp.aes.WXBizMsgCrypt;
import org.jeewx.api.third.JwThirdAPI;
import org.jeewx.api.third.model.ApiComponentToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskExecutor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.danskin.wechat.api.client.WeiXinOpenApiClient;
import com.danskin.wechat.cache.JedisClient;
import com.danskin.wechat.constant.DanskinConstants;
import com.danskin.wechat.dto.SendCouponResultDto;
import com.danskin.wechat.entity.CrmBrandInfo;
import com.danskin.wechat.entity.SceneQrcode;
import com.danskin.wechat.entity.WxAuthTicket;
import com.danskin.wechat.entity.WxCardConfig;
import com.danskin.wechat.entity.WxFansCard;
import com.danskin.wechat.entity.WxFansMsg;
import com.danskin.wechat.entity.WxMediaPlatform;
import com.danskin.wechat.entity.WxMessage;
import com.danskin.wechat.entity.WxMessageNews;
import com.danskin.wechat.entity.WxMsgReplyDetail;
import com.danskin.wechat.model.AccessResponse;
import com.danskin.wechat.service.CouponService;
import com.danskin.wechat.service.CrmBrandInfoService;
import com.danskin.wechat.service.CustInfoService;
import com.danskin.wechat.service.WechatMsgTemplateService;
import com.danskin.wechat.service.WxMessageService;
import com.danskin.wechat.util.ConvertUtils;
import com.danskin.wechat.util.EncryptUtil;
import com.danskin.wechat.util.LogUtil;
import com.danskin.wechat.util.PropertyUtil;
import com.danskin.wechat.util.StringUtil;
import com.danskin.wechat.vo.WxMenuInfoVo;

/**
 * 微信第三方平台对外开放接口
 * 
 * @author Allen Liu
 *
 */
@RestController
@RequestMapping("api/wechat")
public class WechatController extends BaseApiController {

	@Autowired
	public CustInfoService custInfoService;

	@Autowired
	public CouponService couponService;

	@Autowired
	public WechatMsgTemplateService msgTemplateService;

	@Autowired
	private WxMessageService wxMessageService;

	@Autowired
	private CrmBrandInfoService crmBrandInfoService;

	@Autowired
	private TaskExecutor executor;
	@Autowired
	private JedisClient jedis;

	private final String USER_COUPON_KEY = "USER_COUPON_KEY";

	/*
	 * 测试公众号原始ID
	 */
	@Value("${test_originid}")
	private String TEST_ORIGINID;
	@Value("${domain}")
	private String DOMAIN;

	@RequestMapping("/test2")
	public Object test2(HttpServletRequest request) {

		String test_mp = PropertyUtil.get("test_mp");

		// 线程池+同步块
		final int i = 0;
		executor.execute(new Runnable() {
			@Override
			public void run() {

			}
		});

		// try {
		// Thread.sleep(10 * 1000);
		// } catch (InterruptedException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		return DOMAIN + "||" + test_mp;
	}

	@RequestMapping(value = "test", method = RequestMethod.POST)
	public void test(@RequestBody Map<String, Object> map, HttpServletRequest request, HttpServletResponse response)
			throws IOException, AesException, DocumentException, WexinReqException {

		String front_domain = PropertyUtil.get("front_domain");
		output(response, front_domain); // 输出响应的内容。

	}

	/**
	 * 授权事件接收
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 * @throws AesException
	 * @throws DocumentException
	 */
	@RequestMapping(value = "/receiveTicket")
	public void receiveAuthorizeEvent(HttpServletRequest request, HttpServletResponse response)
			throws IOException, AesException, DocumentException {

		processAuthorizeEvent(request);
		output(response, "success"); // 输出响应的内容。
	}

	/**
	 * 公众号消息与事件接收
	 * 
	 * @param appId
	 * @param request
	 * @param response
	 * @throws IOException
	 * @throws AesException
	 * @throws DocumentException
	 */
	@RequestMapping(value = "/{appid}/callback")
	public void acceptMessageAndEvent(@PathVariable("appid") String appId, HttpServletRequest request,
			HttpServletResponse response) throws IOException, AesException, DocumentException {
		String msgSignature = request.getParameter("msg_signature");
		// LogUtil.info("第三方平台全网发布-------------{appid}/callback-----------验证开始。。。。msg_signature="
		// + msgSignature);
		LogUtil.info("公众号AppID：" + appId);
		if (!StringUtils.isNotBlank(msgSignature))
			return;// 微信推送给第三方开放平台的消息一定是加过密的，无消息加密无法解密消息

		StringBuilder sb = new StringBuilder();
		BufferedReader in = request.getReader();
		String line;
		while ((line = in.readLine()) != null) {
			sb.append(line);
		}
		in.close();

		String xml = sb.toString();
		// Document doc = DocumentHelper.parseText(xml);
		// Element rootElt = doc.getRootElement();
		// String toUserName = rootElt.elementText("ToUserName");
		String testMp = PropertyUtil.get("test_mp");
		if (testMp.equals("1")) {

			checkWeixinAllNetworkCheckToPublish(request, response, xml);
		} else {

			checkWeixinAllNetworkCheck(request, response, xml, appId);
		}

		// 微信全网测试账号
		// if (StringUtils.equalsIgnoreCase(toUserName, APPID)) {
		// } else {
		//
		// }
	}

	/**
	 * 处理授权事件的推送
	 * 
	 * @param request
	 * @throws IOException
	 * @throws AesException
	 * @throws DocumentException
	 */
	public void processAuthorizeEvent(HttpServletRequest request) throws IOException, DocumentException, AesException {
		String nonce = request.getParameter("nonce");
		String timestamp = request.getParameter("timestamp");
		String signature = request.getParameter("signature");
		String msgSignature = request.getParameter("msg_signature");

		if (!StringUtils.isNotBlank(msgSignature))
			return;// 微信推送给第三方开放平台的消息一定是加过密的，无消息加密无法解密消息
		boolean isValid = checkSignature(COMPONENT_TOKEN, signature, timestamp, nonce);
		if (isValid) {
			StringBuilder sb = new StringBuilder();
			BufferedReader in = request.getReader();
			String line;
			while ((line = in.readLine()) != null) {
				sb.append(line);
			}
			String xml = sb.toString();
			// String encodingAesKey = COMPONENT_ENCODINGAESKEY;// 第三方平台组件加密密钥
			// String appId = getAuthorizerAppidFromXml(xml);//
			// 此时加密的xml数据中ToUserName是非加密的，解析xml获取即可
			// LogUtil.info("第三方平台全网发布-------------appid----------getAuthorizerAppidFromXml(xml)-----------appId="+appId);

			LogUtil.info("第三方平台授权事件-----------------------原始 Xml=" + xml);
			WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
			xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);
			LogUtil.info("第三方平台授权事件-----------------------解密后 Xml=" + xml);
			processAuthorizationEvent(xml);
		}
	}

	/**
	 * 判断是否加密
	 * 
	 * @param token
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @return
	 */
	public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {

		boolean flag = false;
		if (signature != null && !signature.equals("") && timestamp != null && !timestamp.equals("") && nonce != null
				&& !nonce.equals("")) {
			String sha1 = "";
			String[] ss = new String[] { token, timestamp, nonce };
			Arrays.sort(ss);
			for (String s : ss) {
				sha1 += s;
			}

			sha1 = EncryptUtil.SHA1(sha1);

			if (sha1.equals(signature)) {
				flag = true;
			}
		}
		return flag;
	}

	/**
	 * 保存Ticket
	 * 
	 * @param xml
	 */
	void processAuthorizationEvent(String xml) {
		Document doc;
		try {
			doc = DocumentHelper.parseText(xml);
			Element rootElt = doc.getRootElement();
			String infoType = rootElt.elementText("InfoType");

			if (infoType.equalsIgnoreCase("component_verify_ticket")) {

				String ticket = rootElt.elementText("ComponentVerifyTicket");
				LogUtil.info("微信推送component_verify_ticket消息10分钟一次-----------" + ticket);
				if (ConvertUtils.isNotEmpty(ticket)) {

					WxAuthTicket entity = new WxAuthTicket();
					entity.setInfoType(infoType);
					entity.setTicket(ticket);
					entity.setAppId(COMPONENT_APPID);
					entity.setGetTicketTime(new Date());

					wechatOpService.saveOrUpdateTicket(entity);
				}
			} else if (infoType.equalsIgnoreCase("authorized")) { // 授权成功通知

			} else if (infoType.equalsIgnoreCase("unauthorized")) { // 取消授权通知
				WxMediaPlatform entity = new WxMediaPlatform();
				entity.setAppId(rootElt.elementText("AuthorizerAppid"));
				entity.setStatus(0); // 更改为取消接入第三方平台

				wechatOpService.saveWxMediaPlatform(entity);
			} else if (infoType.equalsIgnoreCase("updateauthorized")) { // 授权更新通知

			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取授权的Appid
	 * 
	 * @param xml
	 * @return
	 */
	// private String getAuthorizerAppidFromXml(String xml) {
	// Document doc;
	// try {
	// doc = DocumentHelper.parseText(xml);
	// Element rootElt = doc.getRootElement();
	// String toUserName = rootElt.elementText("ToUserName");
	// return toUserName;
	// } catch (DocumentException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// return null;
	// }

	/**
	 * 全网发布测试
	 * 
	 * @param request
	 * @param response
	 * @param xml
	 * @throws DocumentException
	 * @throws IOException
	 * @throws AesException
	 */
	public void checkWeixinAllNetworkCheckToPublish(HttpServletRequest request, HttpServletResponse response,
			String xml) throws DocumentException, IOException, AesException {
		LogUtil.info("全网发布接入检测消息反馈开始---------------测试公众号原始ID，APPID=" + TEST_ORIGINID);

		String nonce = request.getParameter("nonce");
		String timestamp = request.getParameter("timestamp");
		String msgSignature = request.getParameter("msg_signature");

		LogUtil.info("全网发布接入检测---消息、事件接收参数-----------nonce=" + nonce + "&timestamp=" + timestamp + "&msgSignature="
				+ msgSignature);
		LogUtil.info("全网发布接入检测---消息、事件接收-----------原始 Xml=" + xml);

		try {
			WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
			xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);
			LogUtil.info("全网发布接入检测---消息、事件接收-----------解密后xml=" + xml);

			Document doc = DocumentHelper.parseText(xml);
			Element rootElt = doc.getRootElement();
			String msgType = rootElt.elementText("MsgType");
			String toUserName = rootElt.elementText("ToUserName");
			String fromUserName = rootElt.elementText("FromUserName");
			if ("event".equals(msgType)) {
				// LogUtil.info("---全网发布接入检测--step.3-----------事件消息--------");
				String event = rootElt.elementText("Event");

				// 全网发布
				String content = event + "from_callback";
				replyTextMessage(request, response, content, toUserName, fromUserName);
			} else if ("text".equals(msgType)) {
				// LogUtil.info("---全网发布接入检测--step.3-----------文本消息--------");
				String content = rootElt.elementText("Content");

				// 全网发布-------------------------------
				if ("TESTCOMPONENT_MSG_TYPE_TEXT".equals(content)) {
					String returnContent = content + "_callback";
					replyTextMessage(request, response, returnContent, toUserName, fromUserName);
				} else if (StringUtils.startsWithIgnoreCase(content, "QUERY_AUTH_CODE")) {
					output(response, "");
					// 接下来客服API再回复一次消息
					replyApiTextMessage(request, response, content.split(":")[1], fromUserName);
				}
			}
		} catch (Exception e) {
			LogUtil.error("全网发布接入检测异常：" + e.getMessage());
		}
	}

	/**
	 * 正式接入接收消息
	 * 
	 * @param request
	 * @param response
	 * @param xml
	 * @param appId
	 * @throws DocumentException
	 * @throws IOException
	 * @throws AesException
	 */
	public void checkWeixinAllNetworkCheck(HttpServletRequest request, HttpServletResponse response, String xml,
			String appId) throws DocumentException, IOException, AesException {
		WxMediaPlatform mediaPlatform = this.getMPWithAccessToken(appId);
		if (mediaPlatform == null) {
			LogUtil.error("公众号消息与事件接收，无效的AppId：" + appId);
			return;
		}
		String nonce = request.getParameter("nonce");
		String timestamp = request.getParameter("timestamp");
		String msgSignature = request.getParameter("msg_signature");

		LogUtil.info("---消息、事件接收-----------原始 Xml=" + xml);
		WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
		xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);
		LogUtil.info("---消息、事件接收-----------解密后xml=" + xml);

		Document doc = DocumentHelper.parseText(xml);
		Element rootElt = doc.getRootElement();
		String msgType = rootElt.elementText("MsgType");
		String toUserName = rootElt.elementText("ToUserName");
		String fromUserName = rootElt.elementText("FromUserName");
		if ("event".equals(msgType)) {
			// LogUtil.info("---全网发布接入检测--step.3-----------事件消息--------");
			String event = rootElt.elementText("Event");
			replyEventMessage(request, response, event, toUserName, fromUserName, rootElt, mediaPlatform);
		} else if ("text".equals(msgType)) {
			// LogUtil.info("---全网发布接入检测--step.3-----------文本消息--------");
			String content = rootElt.elementText("Content");
			processTextMessage(request, response, content, toUserName, fromUserName, rootElt, mediaPlatform);
		}
	}

	public void replyEventMessage(HttpServletRequest request, HttpServletResponse response, String event,
			String toUserName, String fromUserName, Element rootElt, WxMediaPlatform mediaPlatform)
			throws DocumentException, IOException {

		if (event.equalsIgnoreCase("user_get_card")) { // 领取会员卡和券

			String cardId = rootElt.elementText("CardId");
			String userCardCode = rootElt.elementText("UserCardCode");

			// 保存粉丝领取卡券记录
			WxFansCard entity = new WxFansCard();
			entity.setMpId(mediaPlatform.getId());
			entity.setOpenId(fromUserName);
			entity.setWxCardId(cardId);
			entity.setUserCardCode(userCardCode);
			entity.setMembershipNumber(userCardCode);

			// 设置券为“已领取”状态
			WxCardConfig cardConfig = wechatOpService.findCardConfig(mediaPlatform.getId(), cardId);
			if (cardConfig != null
					&& !cardConfig.getCardType().equals(DanskinConstants.WX_CARD_CONFIG_CARD_TYPE_MEMBER_CARD)) {

				// 如果是券，则修改券的状态为“已领取”
				couponService.setCustCouponWxGet(mediaPlatform.getId(), userCardCode);
				// 如果是券，默认激活状态
				entity.setStatus((byte) 1);
			}

			// 保存粉丝领取卡券记录
			wechatOpService.saveFansCard(entity);

		} else if (event.equalsIgnoreCase("submit_membercard_user_info")) { // 接收粉丝提交的信息，进行会员卡激活操作（只针对会员卡激活）
			String access_token = mediaPlatform.getAccessToken();// this.getMPAccessToken(mediaPlatform.getAppId());

			String cardId = rootElt.elementText("CardId");
			String userCardCode = rootElt.elementText("UserCardCode");
			// 获取用户信息，更新手机号码
			JSONObject memberCard = WeiXinOpenApiClient.createInstance().getMemberCardUserInfo(access_token, cardId,
					userCardCode);
			// LogUtil.info("获取用户信息：" + memberCard.toJSONString());
			if (memberCard != null) {
				JSONObject user_info = memberCard.getJSONObject("user_info");
				JSONArray fields = user_info.getJSONArray("common_field_list");
				String mobile = "";// fields.getJSONObject(0).getString("value");//这里是个坑，必须指定获取USER_FORM_INFO_FLAG_MOBILE，才能获取到手机号
				for (int i = 0; i < fields.size(); i++) {
					JSONObject field = fields.getJSONObject(i);
					if (field != null && field.getString("name").equalsIgnoreCase("USER_FORM_INFO_FLAG_MOBILE")) {
						mobile = field.getString("value");
						break;
					}
				}

				// 创建一个会员或绑定会员
				custInfoService.activateMemberInfo(access_token, mediaPlatform.getId(), mediaPlatform.getAppId(),
						mobile, fromUserName, cardId, userCardCode);

			}
		} else if (event.equalsIgnoreCase("user_view_card")) { // 用户打开微信卡包查看时触发
			// <xml><ToUserName><![CDATA[gh_c9d580fc07f0]]></ToUserName>
			// <FromUserName><![CDATA[o02XP1UXZxxshYsTpFGwIhfjCC2E]]></FromUserName>
			// <CreateTime>1509450212</CreateTime>
			// <MsgType><![CDATA[event]]></MsgType>
			// <Event><![CDATA[user_view_card]]></Event>
			// <CardId><![CDATA[p02XP1UXpsPdSxZbdX9Kj4Cw6NQk]]></CardId>
			// <UserCardCode><![CDATA[001674252185]]></UserCardCode>
			// <OuterStr><![CDATA[]]></OuterStr>
			// </xml>

			String access_token = mediaPlatform.getAccessToken();

			String cardId = rootElt.elementText("CardId");
			String userCardCode = rootElt.elementText("UserCardCode");

			WxFansCard fansCard = new WxFansCard();
			fansCard.setWxCardId(cardId);
			fansCard.setUserCardCode(userCardCode);

			custInfoService.userViewCard(access_token, fromUserName, fansCard);

		} else if (event.equalsIgnoreCase("CLICK")) { // 菜单点击事件
			String menuKey = rootElt.elementText("EventKey");
			WxMenuInfoVo menuInfo = wechatOpService.findMenuInfoByMenuKey(mediaPlatform.getId(), menuKey);
			if (menuInfo != null && menuInfo.getType().equals("1")) { // 点击事件
				if (menuInfo.getMsgType().equals("text")) { // 回复文本
					replyTextMessage(request, response, menuInfo.getContent(), toUserName, fromUserName);
				} else if (menuInfo.getMsgType().equals("image")) { // 回复图片
					replyImageMessage(request, response, menuInfo.getMediaId(), toUserName, fromUserName);
				} else if (menuInfo.getMsgType().equals("news")) { // 回复图文
					String access_token = mediaPlatform.getAccessToken();

					replyKfMpNewsMessage(access_token, fromUserName, menuInfo.getMediaId());
				}

				// 记录菜单点击数据for报表
				wechatOpService.saveMenuClick(menuInfo, fromUserName);
			}
		} else if (event.equalsIgnoreCase("view")) {// 菜单跳转事件
			String menuKey = rootElt.elementText("EventKey");
			WxMenuInfoVo menuInfo = wechatOpService.findMenuInfoByMenuKey(mediaPlatform.getId(), menuKey);
			if (menuInfo != null && menuInfo.getType().equals("2")) {

				// 记录菜单点击数据for报表
				wechatOpService.saveMenuClick(menuInfo, fromUserName);
			}
		} else if (event.equalsIgnoreCase("subscribe")) { // 关注事件
			String access_token = mediaPlatform.getAccessToken();// this.getMPAccessToken(mediaPlatform.getAppId());
			wechatOpService.saveFansInfo(access_token, mediaPlatform.getId(), fromUserName, null);

			// 关注回复
			List<WxMsgReplyDetail> msgReplyList = wechatOpService.findReplyDetail(mediaPlatform.getId(),
					"subscription");
			if (msgReplyList != null && msgReplyList.size() > 0) {
				WxMsgReplyDetail msgReply = msgReplyList.get(0);
				replyFansMsg(request, response, toUserName, fromUserName, access_token, msgReply);
			}
			// 扫描二维码，记录扫描数据
			String eventKey = rootElt.elementText("EventKey").replace("qrscene_", "");// 截取qrscene_开始
			try {
				SceneQrcode qrCode = wechatOpService.saveQrcodeStatis(mediaPlatform.getId(), eventKey, fromUserName, 0);
				if (qrCode != null && qrCode.getMessageId() != null && qrCode.getMessageId() > 0) {
					WxMessage wxMessage = wxMessageService.getWxMessage(qrCode.getMessageId());
					if (wxMessage != null) {
						if (wxMessage.getMsgType().equals(1)) { // 文本
							// replyTextMessage(request, response,
							// wxMessage.getReplyText(), toUserName,
							// fromUserName);
							replyKfTextMessage(access_token, fromUserName, wxMessage.getReplyText());
						} else if (wxMessage.getMsgType().equals(2)) { // 图片
							// replyImageMessage(request, response,
							// wxMessage.getMediaId(), toUserName,
							// fromUserName);
							replyKfImageMessage(access_token, fromUserName, wxMessage.getMediaId());
						} else if (wxMessage.getMsgType().equals(3)) { // 微信图文
							// String accessToken =
							// mediaPlatform.getAccessToken();
							replyKfMpNewsMessage(access_token, fromUserName, wxMessage.getMediaId());
						} else if (wxMessage.getMsgType().equals(4)) { // 自定义图文
							List<WxMessageNews> newsList = wxMessageService.getWxMessageNews(wxMessage.getId());
							if (newsList != null) {
								replyNewsMessage(response, newsList, toUserName, fromUserName);
							}
						}
					}

					// 发券 2017-12-07 by liulikui
					SendCouponToFans(qrCode, fromUserName, mediaPlatform);

				}
			} catch (Exception e) {
				LogUtil.error("关注扫码异常：" + e);
			}

		} else if (event.equalsIgnoreCase("unsubscribe")) { // 取消关注事件
			String access_token = mediaPlatform.getAccessToken();// this.getMPAccessToken(mediaPlatform.getAppId());
			wechatOpService.saveFansInfo(access_token, mediaPlatform.getId(), fromUserName, null);
		} else if (event.equalsIgnoreCase("SCAN")) { // 扫码事件
			String eventKey = rootElt.elementText("EventKey");
			try {

				SceneQrcode qrCode = wechatOpService.saveQrcodeStatis(mediaPlatform.getId(), eventKey, fromUserName, 1);
				if (qrCode != null && qrCode.getMessageId() != null && qrCode.getMessageId() > 0) {
					WxMessage wxMessage = wxMessageService.getWxMessage(qrCode.getMessageId());
					if (wxMessage != null) {
						if (wxMessage.getMsgType().equals(1)) { // 文本
							replyTextMessage(request, response, wxMessage.getReplyText(), toUserName, fromUserName);

						} else if (wxMessage.getMsgType().equals(2)) { // 图片
							replyImageMessage(request, response, wxMessage.getMediaId(), toUserName, fromUserName);
						} else if (wxMessage.getMsgType().equals(3)) { // 微信图文
							String accessToken = mediaPlatform.getAccessToken();
							replyKfMpNewsMessage(accessToken, fromUserName, wxMessage.getMediaId());
						} else if (wxMessage.getMsgType().equals(4)) { // 自定义图文
							List<WxMessageNews> newsList = wxMessageService.getWxMessageNews(wxMessage.getId());
							if (newsList != null) {
								replyNewsMessage(response, newsList, toUserName, fromUserName);
							}
						}
					}

					// 发券 2017-12-07 by liulikui
					SendCouponToFans(qrCode, fromUserName, mediaPlatform);

				}
			} catch (Exception e) {
				LogUtil.error("扫码异常：" + e);
			}

		}

	}

	private void SendCouponToFans(SceneQrcode qrCode, String fromUserName, WxMediaPlatform mediaPlatform) {

		if (!StringUtil.isNullOrEmpty(qrCode.getCouponTemplateId())) {
			String myKey = USER_COUPON_KEY + ":" + qrCode.getCouponTemplateId() + ":" + fromUserName;
			String string = jedis.get(myKey);
			if (!StringUtils.isBlank(string)) {
				return;
			}

			final WxMediaPlatform mediaPlatformF = mediaPlatform;
			final SceneQrcode qrCodeF = qrCode;
			final String fromUserNameF = fromUserName;
			final String myKeyF = myKey;

			executor.execute(new Runnable() {
				@Override
				public void run() {

					CrmBrandInfo brandInfo = crmBrandInfoService.selectCrmBrandInfoByMpId(mediaPlatformF.getId());
					if (brandInfo != null) {
						@SuppressWarnings("unchecked")
						AccessResponse<Object> oo = (AccessResponse<Object>) custInfoService.sendCouponToCust(
								qrCodeF.getCouponTemplateId(), null, fromUserNameF, mediaPlatformF.getId(),
								brandInfo.getBrandId(), qrCodeF.getName() + qrCodeF.getCouponTemplateId());
						if (oo.getErrorCode().equals("0")) {
							jedis.set(myKeyF, "1");
							jedis.expire(myKeyF, 3600 * 24 * 10);
						}
					}
				}
			});
		}
	}

	public void processTextMessage(HttpServletRequest request, HttpServletResponse response, String content,
			String toUserName, String fromUserName, Element rootElt, WxMediaPlatform mediaPlatform)
			throws IOException, DocumentException {

		WxFansMsg entity = new WxFansMsg();
		entity.setMpId(mediaPlatform.getId());
		entity.setMsgType(rootElt.elementText("MsgType"));
		entity.setOpenId(rootElt.elementText("FromUserName"));
		entity.setMsgId(Long.valueOf(rootElt.elementText("MsgId")));
		entity.setContent(content);
		entity.setCreatedTime(new Date(Long.valueOf(rootElt.elementText("CreateTime")) * 1000));

		wechatOpService.saveFansMsg(entity);

		// 关键字自动回复功能
		String access_token = mediaPlatform.getAccessToken();// this.getMPAccessToken(mediaPlatform.getAppId());
		WxMsgReplyDetail msgReply = wechatOpService.findReplyDetailKeyword(mediaPlatform.getId(), content);
		if (msgReply != null) {
			replyFansMsg(request, response, toUserName, fromUserName, access_token, msgReply);

		} else { // 自动回复
			List<WxMsgReplyDetail> msgReplyList = wechatOpService.findReplyDetail(mediaPlatform.getId(), "auto");
			if (msgReplyList != null && msgReplyList.size() > 0) {
				WxMsgReplyDetail autoMsgReply = msgReplyList.get(0);
				replyFansMsg(request, response, toUserName, fromUserName, access_token, autoMsgReply);
			}
			// else {
			// replyTextMessage(request, response, "您好，需要什么帮助。", toUserName,
			// fromUserName);
			// }
		}
	}

	private void replyFansMsg(HttpServletRequest request, HttpServletResponse response, String toUserName,
			String fromUserName, String access_token, WxMsgReplyDetail msgReply) throws DocumentException, IOException {

		if (msgReply.getMsgType().equals("text")) { // 回复文本
			replyTextMessage(request, response, msgReply.getReplyText(), toUserName, fromUserName);
		} else if (msgReply.getMsgType().equals("image")) { // 回复图片
			replyImageMessage(request, response, msgReply.getMediaId(), toUserName, fromUserName);
		} else if (msgReply.getMsgType().equals("news")) { // 回复图文
			// JSONObject json =
			// WeiXinOpenApiClient.createInstance().getMaterial(access_token,
			// msgReply.getMediaId());
			// if (json != null && json.containsKey("news_item")) {
			// JSONArray items = json.getJSONArray("news_item");
			// replyNewsMessage(request, response, items, toUserName,
			// fromUserName);
			// }
			replyKfMpNewsMessage(access_token, fromUserName, msgReply.getMediaId());
		}
	}

	public void replyApiTextMessage(HttpServletRequest request, HttpServletResponse response, String auth_code,
			String fromUserName) throws DocumentException, IOException {
		String authorization_code = auth_code;
		// 得到微信授权成功的消息后，应该立刻进行处理！！相关信息只会在首次授权的时候推送过来
		try {
			ApiComponentToken apiComponentToken = new ApiComponentToken();
			apiComponentToken.setComponent_appid(COMPONENT_APPID);
			apiComponentToken.setComponent_appsecret(COMPONENT_APPSECRET);
			WxAuthTicket entity = wechatOpService.getAuthTicket(COMPONENT_APPID);
			apiComponentToken.setComponent_verify_ticket(entity.getTicket());
			String component_access_token = JwThirdAPI.getAccessToken(apiComponentToken);

			// component_access_token = " + component_access_token+
			// "---------authorization_code = " + authorization_code);
			net.sf.json.JSONObject authorizationInfoJson = JwThirdAPI.getApiQueryAuthInfo(COMPONENT_APPID,
					authorization_code, component_access_token);
			// 获取authorizationInfoJson = " + authorizationInfoJson);
			net.sf.json.JSONObject infoJson = authorizationInfoJson.getJSONObject("authorization_info");
			String authorizer_access_token = infoJson.getString("authorizer_access_token");

			Map<String, Object> obj = new HashMap<String, Object>();
			Map<String, Object> msgMap = new HashMap<String, Object>();
			String msg = auth_code + "_from_api";
			msgMap.put("content", msg);

			obj.put("touser", fromUserName);
			obj.put("msgtype", "text");
			obj.put("text", msgMap);
			JwThirdAPI.sendMessage(obj, authorizer_access_token);
		} catch (WexinReqException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 回复客服消息-发送文本消息
	 * 
	 * @param request
	 * @param response
	 * @param accessToken
	 * @param fromUserName
	 * @param text
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void replyKfTextMessage(String accessToken, String fromUserName, String text)
			throws DocumentException, IOException {
		// {
		// "touser":"OPENID",
		// "msgtype":"text",
		// "text":
		// {
		// "content":"Hello World"
		// }
		// }
		Map<String, Object> obj = new HashMap<String, Object>();

		obj.put("touser", fromUserName);
		obj.put("msgtype", "text");

		Map<String, Object> msgMap = new HashMap<String, Object>();
		msgMap.put("content", text);
		obj.put("text", msgMap);

		JwThirdAPI.sendMessage(obj, accessToken);
	}

	/**
	 * 回复客服消息-发送图片消息
	 * 
	 * @param accessToken
	 * @param fromUserName
	 * @param mediaId
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void replyKfImageMessage(String accessToken, String fromUserName, String mediaId)
			throws DocumentException, IOException {
		// {
		// "touser":"OPENID",
		// "msgtype":"image",
		// "image":
		// {
		// "media_id":"MEDIA_ID"
		// }
		// }
		Map<String, Object> obj = new HashMap<String, Object>();

		obj.put("touser", fromUserName);
		obj.put("msgtype", "image");

		Map<String, Object> msgMap = new HashMap<String, Object>();
		msgMap.put("media_id", mediaId);
		obj.put("image", msgMap);

		JwThirdAPI.sendMessage(obj, accessToken);
	}

	/**
	 * 回复客服消息-发送图文消息（点击跳转到图文消息页面） 图文消息条数限制在8条以内
	 * 
	 * @param accessToken
	 * @param fromUserName
	 * @param mediaId
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void replyKfMpNewsMessage(String accessToken, String fromUserName, String mediaId)
			throws DocumentException, IOException {
		// {
		// "touser":"OPENID",
		// "msgtype":"mpnews",
		// "mpnews":
		// {
		// "media_id":"MEDIA_ID"
		// }
		// }
		Map<String, Object> obj = new HashMap<String, Object>();

		obj.put("touser", fromUserName);
		obj.put("msgtype", "mpnews");

		Map<String, Object> msgMap = new HashMap<String, Object>();
		msgMap.put("media_id", mediaId);
		obj.put("mpnews", msgMap);

		JwThirdAPI.sendMessage(obj, accessToken);

	}

	/**
	 * 验证是否过期
	 * 
	 * @param accessTokenExpires
	 * @return
	 */
	boolean isExpired(long accessTokenExpires) {
		return false;
	}

	/**
	 * 被动回复消息-文本消息
	 * 
	 * @param request
	 * @param response
	 * @param content
	 * @param toUserName
	 * @param fromUserName
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void replyTextMessage(HttpServletRequest request, HttpServletResponse response, String content,
			String toUserName, String fromUserName) throws DocumentException, IOException {
		Long createTime = Calendar.getInstance().getTimeInMillis() / 1000;
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		sb.append("<ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>");
		sb.append("<FromUserName><![CDATA[" + toUserName + "]]></FromUserName>");
		sb.append("<CreateTime>" + createTime + "</CreateTime>");
		sb.append("<MsgType><![CDATA[text]]></MsgType>");
		sb.append("<Content><![CDATA[" + content + "]]></Content>");
		sb.append("</xml>");
		String replyMsg = sb.toString();

		String returnvaleue = "";
		try {
			WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
			returnvaleue = pc.encryptMsg(replyMsg, createTime.toString(), "easemob");
		} catch (AesException e) {
			e.printStackTrace();
		}
		output(response, returnvaleue);
	}

	/**
	 * 被动回复消息-图片消息
	 * 
	 * @param request
	 * @param response
	 * @param mediaId
	 * @param toUserName
	 * @param fromUserName
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void replyImageMessage(HttpServletRequest request, HttpServletResponse response, String mediaId,
			String toUserName, String fromUserName) throws DocumentException, IOException {
		Long createTime = Calendar.getInstance().getTimeInMillis() / 1000;
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		sb.append("<ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>");
		sb.append("<FromUserName><![CDATA[" + toUserName + "]]></FromUserName>");
		sb.append("<CreateTime>" + createTime + "</CreateTime>");
		sb.append("<MsgType><![CDATA[image]]></MsgType>");
		sb.append("<Image>");
		sb.append("<MediaId><![CDATA[" + mediaId + "]]></MediaId>");
		sb.append("</Image>");
		sb.append("</xml>");
		String replyMsg = sb.toString();

		String returnvaleue = "";
		try {
			WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
			returnvaleue = pc.encryptMsg(replyMsg, createTime.toString(), "easemob");
		} catch (AesException e) {
			e.printStackTrace();
		}
		output(response, returnvaleue);
	}

	/**
	 * 被动回复消息-图文消息（点击跳转到图文消息页面）
	 * 
	 * @param request
	 * @param response
	 * @param items
	 * @param toUserName
	 * @param fromUserName
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void replyMpNewsMessage(HttpServletRequest request, HttpServletResponse response, JSONArray items,
			String toUserName, String fromUserName) throws DocumentException, IOException {
		Long createTime = Calendar.getInstance().getTimeInMillis() / 1000;
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		sb.append("<ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>");
		sb.append("<FromUserName><![CDATA[" + toUserName + "]]></FromUserName>");
		sb.append("<CreateTime>" + createTime + "</CreateTime>");
		sb.append("<MsgType><![CDATA[news]]></MsgType>");
		sb.append("<ArticleCount>" + items.size() + "</ArticleCount>");
		sb.append("<Articles>");
		for (int i = 0; i < items.size(); i++) {
			JSONObject json = items.getJSONObject(i);
			sb.append("<item>");

			sb.append("<Title><![CDATA[" + json.getString("title") + "]]></Title>");
			sb.append("<Description><![CDATA[" + json.getString("digest") + "]]></Description>");
			sb.append("<PicUrl><![CDATA[" + json.getString("thumb_url") + "]]></PicUrl>");
			sb.append("<Url><![CDATA[" + json.getString("url") + "]]></Url>");

			sb.append("</item>");
		}

		sb.append("</Articles>");
		sb.append("</xml>");
		String replyMsg = sb.toString();

		String returnvaleue = "";
		try {
			WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
			returnvaleue = pc.encryptMsg(replyMsg, createTime.toString(), "easemob");
		} catch (AesException e) {
			e.printStackTrace();
		}
		output(response, returnvaleue);
	}

	/**
	 * 被动回复消息-自定义图文消息（点击跳转到外链）
	 * 
	 * @param response
	 * @param newsList
	 * @param toUserName
	 * @param fromUserName
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void replyNewsMessage(HttpServletResponse response, List<WxMessageNews> newsList, String toUserName,
			String fromUserName) throws DocumentException, IOException {
		Long createTime = Calendar.getInstance().getTimeInMillis() / 1000;
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		sb.append("<ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>");
		sb.append("<FromUserName><![CDATA[" + toUserName + "]]></FromUserName>");
		sb.append("<CreateTime>" + createTime + "</CreateTime>");
		sb.append("<MsgType><![CDATA[news]]></MsgType>");
		sb.append("<ArticleCount>" + newsList.size() + "</ArticleCount>");
		sb.append("<Articles>");
		for (WxMessageNews news : newsList) {
			sb.append("<item>");

			sb.append("<Title><![CDATA[" + news.getTitle() + "]]></Title>");
			String description = news.getDescription();
			if (StringUtil.isNullOrEmpty(description)) {
				description = "";
			}
			sb.append("<Description><![CDATA[" + description + "]]></Description>");
			sb.append("<PicUrl><![CDATA[" + news.getPicUrl() + "]]></PicUrl>");
			sb.append("<Url><![CDATA[" + news.getLinkUrl() + "]]></Url>");

			sb.append("</item>");
		}

		sb.append("</Articles>");
		sb.append("</xml>");
		String replyMsg = sb.toString();

		String returnvaleue = "";
		try {
			WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
			returnvaleue = pc.encryptMsg(replyMsg, createTime.toString(), "easemob");
		} catch (AesException e) {
			e.printStackTrace();
		}
		output(response, returnvaleue);
	}

	/**
	 * 工具类：回复微信服务器"文本消息"
	 * 
	 * @param response
	 * @param returnvaleue
	 */
	public void output(HttpServletResponse response, String returnvaleue) {
		try {
			// LogUtil.info("输出：" + returnvaleue);
			PrintWriter pw = response.getWriter();
			pw.write(returnvaleue);
			pw.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
